//////////////////////////////////////////////
// LuaSchedulerTask.h
//
//////////////////////////////////////////////

/// Defines / Macros -------------------------

#pragma once

/// Forward decl -----------------------------

namespace nkAstraeus
{
	class LogManager ;
}

namespace nkScripts
{
	class Environment ;
	class Script ;
}

/// Includes ---------------------------------

// nkMemory
#include <NilkinsMemory/Containers/Buffer.h>
#include <NilkinsMemory/Containers/String.h>
#include <NilkinsMemory/Containers/StringView.h>

#include <NilkinsMemory/Pointers/UniquePtr.h>

// nkScripts
#include <NilkinsScripts/Environments/Functions/FunctionDefines.h>

#include <NilkinsScripts/Environments/ScriptObjects/ScriptObjectReference.h>

// nkTasks
#include <NilkinsTasks/Scheduler/SchedulerTask.h>

/// Internals --------------------------------

namespace nkAstraeus::nkTasksWrap
{
	struct UserDataHolder
	{
		nkMemory::String _typeName ;
		void* _userData = nullptr ;
		bool _owner = false ;

		UserDataHolder () = default ;

		UserDataHolder (void* userData, const nkMemory::StringView& typeName, bool owner)
		:	_typeName (typeName),
			_userData (userData),
			_owner (owner)
		{
			// Nothing to do
		}
	} ;

	struct BinaryDataHolder
	{
		nkMemory::Buffer* _data = nullptr ;
		nkScripts::ScriptObjectReference _ref ;
	} ;
}

/// Class ------------------------------------

namespace nkAstraeus::nkTasksWrap
{
	class LuaSchedulerTask final : public nkTasks::SchedulerTask
	{
		public :

			// Constructor, destructor
			LuaSchedulerTask (nkScripts::Environment* originEnv, LogManager* targetLogManager) noexcept ;
			virtual ~LuaSchedulerTask () ;

			// Getters
			nkMemory::Buffer* getInputBinaryData () const ;
			nkMemory::Buffer* getOutputBinaryData () const ;

			// Setters
			void setWorkEnv (nkScripts::Environment* workEnv) ;
			void setWorkFuncReference (const nkScripts::ScriptObjectReference& reference) ;
			void setInitScript (nkScripts::Script* script) ;
			void setInputBinaryData (nkMemory::Buffer* data, const nkScripts::ScriptObjectReference& ref) ;
			void setOutputBinaryData (nkMemory::Buffer* data) ;
			
			// Manipulation user data
			void addInputUserData (void* ptr, nkMemory::StringView typeName, bool owner) ;
			void addOutputUserData (void* ptr, nkMemory::StringView typeName, bool owner) ;
			const UserDataHolder* getInputUserData (unsigned int index) const ;
			const UserDataHolder* getOutputUserData (unsigned int index) const ;

			// Implementations
			virtual void onAsyncWork () override ;
			virtual void onSync () override ;

		private :

			// Environnements création / work
			nkScripts::Environment* _originEnv ;
			nkScripts::Environment* _workEnv ;

			// Les fonctions nécessaires sérialisées
			nkMemory::Buffer _workFuncSerialized ;
			// Userdata à réinjecter
			nkMemory::BufferCast<UserDataHolder> _inputUserDataSerialized ;
			nkMemory::BufferCast<UserDataHolder> _outputUserDataSerialized ;

			// Le script d'init lors du lancement
			nkScripts::Script* _initScript ;

			// Stack d'output toute prête
			nkMemory::BufferCast<nkScripts::FunctionParameter> _outputStack ;

			// Input output binaires
			BinaryDataHolder _inputBinaryData ;
			nkMemory::UniquePtr<nkMemory::Buffer> _outputBinaryData ;

			// Parent system information
			LogManager* _targetLogManager ;
	} ;
}